[R_Mathematics_Calculation_Application] (http://blog.fens.me/r-mathematics/).

Reference: R_Mathematics_Calculation_Application

前言

R是作为统计语言,生来就对数学有良好的支持,一个函数就能实现一种数学计算,所以用R语言做数学计算题特别方便。如果计算器中能嵌入R的计算函数,那么绝对是一种高科技产品。

本文总结了R语言用于初等数学中的各种计算。

目录

基本计算

三角函数计算

复数计算

方程计算

1. 基本计算

1.1 四则运算

加减乘除, 余数, 整除, 绝对值, 判断正负。


a<-10;b<-5

# 加减乘除
a+b;a-b;a*b;a/b
# [1] 15
# [1] 5
# [1] 50
# [1] 2

# 余数,整除
a%%b;a%/%b
# [1] 0
# [1] 2

# 绝对值
abs(-a)
# [1] 10

# 判断正负
sign(-2:3)
# [1] -1 -1  0  1  1  1

1.2 数学计算

幂, 自然常用e的幂, 平方根, 对数

a<-10;b<-5;c<-4

# 幂
c^b;c^-b;c^(b/10)
# [1] 1024
# [1] 0.0009765625
# [1] 2

# 自然常数e
exp(1)
# [1] 2.718282

# 自然常数e的幂
exp(3)
# [1] 20.08554

# 平方根
sqrt(c)
# [1] 2

# 以2为底的对数
log2(c)
# [1] 2

# 以10为底的对数
log10(b)
# [1] 0.69897

# 自定义底的对数
log(c,base = 2)
# [1] 2

# 自然常数e的对数
log(a,base=exp(1))
# [1] 2.302585

# 指数对数操作
log(a^b,base=a)
# [1] 5
log(exp(3))
# [1] 3

1.3 比较计算

==, >, <, !=, <=, >=, isTRUE, identical

a<-10;b<-5

# 比较计算
a==a;a!=b;a>b;a=c
# [1] TRUE
# [1] TRUE
# [1] TRUE
# [1] FALSE
# [1] FALSE
# [1] TRUE

# 判断是否为TRUE
isTRUE(a)
# [1] FALSE
isTRUE(!a)
# [1] FALSE

# 精确比较两个对象
identical(1, as.integer(1))
# [1] FALSE
identical(NaN, -NaN)
# [1] TRUE

f <- function(x) x
g <- compiler::cmpfun(f)
identical(f, g)
# [1] TRUE

1.4 逻辑计算

&, |, &&, ||, xor

x<-c(0,1,0,1)
y<-c(0,0,1,1)

# 只比较第一个元素 &&, ||
x && y;x || y
# [1] FALSE
# [1] FALSE

# S4对象的逻辑运算,比较所有元素 &, |
x & y;x | y
# [1] FALSE FALSE FALSE  TRUE
# [1] FALSE  TRUE  TRUE  TRUE

# 异或
xor(x,y)
# [1] FALSE  TRUE  TRUE FALSE
xor(x,!y)
# [1]  TRUE FALSE FALSE  TRUE

1.5 约数计算

ceiling,floor,trunc,round,signif

# 向上取整
ceiling(5.4)
# [1] 6

# 向下取整
floor(5.8)
# [1] 5

# 取整数
trunc(3.9)
# [1] 3

# 四舍五入
round(5.8)

# 四舍五入,保留2位小数
round(5.8833, 2)
# [1] 5.88

# 四舍五入,保留前2位整数
signif(5990000,2)
# [1] 6e+06

1.6 数组计算

最大, 最小, 范围, 求和, 均值, 加权平均, 连乘, 差分, 秩,,中位数, 分位数, 任意数,全体数

d <- seq(1,10,2);d
# [1] 1 3 5 7 9

# 求最大值,最小值,范围range
max(d);min(d);range(d)
# [1] 9
# [1] 1
# [1] 1 9

# 求和,均值
sum(d),mean(d)
# [1] 25
# [1] 5

# 加权平均
weighted.mean(d,rep(1,5))
# [1] 5
weighted.mean(d,c(1,1,2,2,2))
# [1] 5.75

# 连乘
prod(1:5)
# [1] 120

# 差分
diff(d)
# [1] 2 2 2 2

# 秩
rank(d)
# [1] 1 2 3 4 5

# 中位数
median(d)
# [1] 5

# 分位数
quantile(d)
# 0%  25%  50%  75% 100%
# 1    3    5    7    9

# 任意any,全体all
e<-seq(-3,3);e
# [1] -3 -2 -1  0  1  2  3
any(e<0);all(e<0)
# [1] TRUE
# [1] FALSE

1.7 排列组合计算

排列组合计算: 阶乘, 组合, 排列

# 5!阶乘
factorial(5)
# [1] 120

# 组合, 从5个中选出2个
choose(5, 2)
# [1] 10

# 列出从5个中选出2个的组合所有项
combn(5,2)
#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,]    1    1    1    1    2    2    2    3    3     4
# [2,]    2    3    4    5    3    4    5    4    5     5

# 计算0:10的组合个数
for (n in 0:10) print(choose(n, k = 0:n))
# [1] 1
# [1] 1 1
# [1] 1 2 1
# [1] 1 3 3 1
# [1] 1 4 6 4 1
# [1]  1  5 10 10  5  1
# [1]  1  6 15 20 15  6  1
# [1]  1  7 21 35 35 21  7  1
# [1]  1  8 28 56 70 56 28  8  1
# [1]   1   9  36  84 126 126  84  36   9   1
# [1]   1  10  45 120 210 252 210 120  45  10   1

# 排列,从5个中选出2个
choose(5, 2)*factorial(2)
# [1] 20

1.8 累积计算

累积计算: 累加, 累乘, 最小累积, 最大累积

# 累加
cumsum(1:5)
# [1]  1  3  6 10 15

# 累乘
cumprod(1:5)
# [1]   1   2   6  24 120

e<-seq(-3,3);e
# [1] -3 -2 -1  0  1  2  3

# 最小累积cummin
cummin(e)
# [1] -3 -3 -3 -3 -3 -3 -3
# 最大累积cummax
cummax(e)
# [1] -3 -2 -1  0  1  2  3

两个数组计算

交集, 并集, 差集, 数组是否相等, 取唯一, 查匹配元素的索引, 找重复元素索引

# 定义两个数组向量
x <- c(9:20, 1:5, 3:7, 0:8);x
 # [1]  9 10 11 12 13 14 15 16 17 18 19 20  1  2  3  4  5
# [18]  3  4  5  6  7  0  1  2  3  4  5  6  7  8

y<- 1:10;y
# [1]  1  2  3  4  5  6  7  8  9 10

# 交集
intersect(x,y)
# [1]  9 10  1  2  3  4  5  6  7  8

# 并集
union(x,y)
 # [1]  9 10 11 12 13 14 15 16 17 18 19 20  1  2  3  4  5
# [18]  6  7  0  8

# 差集,从x中排除y
setdiff(x,y)
 # [1] 11 12 13 14 15 16 17 18 19 20  0

# 判断是否相等
setequal(x, y)
# [1] FALSE

# 取唯一
unique(c(x,y))
 # [1]  9 10 11 12 13 14 15 16 17 18 19 20  1  2  3  4  5
# [18]  6  7  0  8

# 找到x在y中存在的元素的索引
which(x %in% y)
 # [1]  1  2 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28
# [18] 29 30 31
which(is.element(x,y))
 # [1]  1  2 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28
# [18] 29 30 31

# 找到重复元素的索引
which(duplicated(x))
 # [1] 18 19 20 24 25 26 27 28 29 30

2. 三角函数计算

2.1 三角函数

在直角三角形中仅有锐角(大小在0到90度之间的角)三角函数的定义。给定一个锐角θ,可以做出一个直角三角形,使得其中的一个内角是θ。设这个三角形中,θ的对边、邻边和斜边长度分别是a、b和h。

Trigonometry_triangle_sim

三角函数的6种关系:正弦,余弦,正切,余切,正割,余割。

  • θ的正弦是对边与斜边的比值:sin θ = a/h

  • θ的余弦是邻边与斜边的比值:cos θ = b/h

  • θ的正切是对边与邻边的比值:tan θ = a/b

  • θ的余切是邻边与对边的比值:cot θ = b/a

  • θ的正割是斜边与邻边的比值:sec θ = h/b

  • θ的余割是斜边与对边的比值:csc θ = h/a

2.1.1 三角函数的特殊值:

# 函数    0     pi/12                  pi/6          pi/4           pi/3             5/(12*pi)              pi/2
# sin     0     (sqrt(6)-sqrt(2))/4    1/2           sqrt(2)/2      sqrt(3)/2        (sqrt(6)+sqrt(2))/4    1
# cos     1     (sqrt(6)+sqrt(2))/4    sqrt(3)/2     sqrt(2)/2      1/2              (sqrt(6)-sqrt(2))/4    0
# tan     0     2-sqrt(3)              sqrt(3)/3     1              sqrt(3)          2+sqrt(3)              NA
# cot     NA    2+sqrt(3)              sqrt(3)       1              sqrt(3)/3        2-sqrt(3)              0
# sec     1     sqrt(6)-sqrt(2)        sqrt(3)*2/3   sqrt(2)        2                sqrt(6)-sqrt(2)        NA
# csc     NA    2                      sqrt(2)       sqrt(3)*2/3    sqrt(6)-sqrt(2)  1                      NA

2.1.2 三角基本函数: 正弦,余弦,正切

# 正弦
sin(0);sin(1);sin(pi/2)
# [1] 0
# [1] 0.841471
# [1] 1

# 余弦
cos(0);cos(1);cos(pi)
# [1] 1
# [1] 0.5403023
# [1] -1

# 正切
tan(0);tan(1);tan(pi)
# [1] 0
# [1] 1.557408
# [1] -1.224647e-16

2.1.3 三角函数画图

接下来,我们用ggplot2包来画出三角函数的图形。

# 加载ggplot2的库
library(ggplot2)
library(scales)

# x坐标
x<-seq(-2*pi,2*pi,by=0.01)

# y坐标
s1<-data.frame(x,y=sin(x),type=rep('sin',length(x)))# 正弦
s2<-data.frame(x,y=cos(x),type=rep('cos',length(x)))# 余弦
s3<-data.frame(x,y=tan(x),type=rep('tan',length(x)))# 正切
s4<-data.frame(x,y=1/tan(x),type=rep('cot',length(x)))# 余切
s5<-data.frame(x,y=1/sin(x),type=rep('sec',length(x)))# 正割
s6<-data.frame(x,y=1/cos(x),type=rep('csc',length(x)))# 余割
df<-rbind(s1,s2,s3,s4,s5,s6)

# 用ggplot2画图
g<-ggplot(df,aes(x,y))
g<-g+geom_line(aes(colour=type,stat='identity'))
g<-g+scale_y_continuous(limits=c(0, 2))
g<-g+scale_x_continuous(breaks=seq(-2*pi,2*pi,by=pi),labels=c("-2*pi","-pi","0","pi","2*pi"))
g

2.2 反三角函数

2.2.1 基本的反三角函数定义:

# 反三角函数      定义          值域
# arcsin(x) = y      sin(y) = x      - pi/2 <= y <= pi/2
# arccos(x) = y      cos(y) = x      0 <= y <= pi,
# arctan(x) = y      tan(y) = x      - pi/2 < y < pi/2
# arccsc(x) = y      csc(y) = x      - pi/2 <= y <= pi/2, y!=0
# arcsec(x) = y      sec(y) = x      0 <= y <= pi, y!=pi/2
# arccot(x) = y      cot(y) = x      0 <  y <  pi

2.2.2 反正弦,反余弦,反正切

# 反正弦asin
asin(0);asin(1)
# [1] 0
# [1] 1.570796  # pi/2=1.570796

# 反余弦acos
acos(0);acos(1)
# [1] 1.570796 # pi/2=1.570796
# [1] 0

# 反正切atan
atan(0);atan(1)
# [1] 0
# [1] 0.7853982 # pi/4=0.7853982

2.2.3 反三角函数画图

# x坐标
x<-seq(-1,1,by=0.005)

# y坐标
s1<-data.frame(x,y=asin(x),type=rep('arcsin',length(x)))
s2<-data.frame(x,y=acos(x),type=rep('arccos',length(x)))
s3<-data.frame(x,y=atan(x),type=rep('arctan',length(x)))
s4<-data.frame(x,y=1/atan(x),type=rep('arccot',length(x)))
s5<-data.frame(x,y=1/asin(x),type=rep('arcsec',length(x)))
s6<-data.frame(x,y=1/acos(x),type=rep('arccsc',length(x)))
df<-rbind(s1,s2,s3,s4,s5,s6)

# 用ggplot2画图
g<-ggplot(df,aes(x,y))
g<-g+geom_line(aes(colour=type,stat='identity'))
g<-g+scale_y_continuous(limits=c(-2*pi,2*pi),breaks=seq(-2*pi,2*pi,by=pi),labels=c("-2*pi","-pi","0","pi","2*pi"))
g

2.3 三角函数公式单元测试

接下来,用单元测试的方式,来描述三角函数的数学公式。通过testthat包,进行单元测试,关于testthat包的安装和使用,请参考文章:在巨人的肩膀前行 催化R包开发

# 加载testthat包
library(testthat)

# 定义变量
a<-5;b<-10

# 平方和公式
# sin(x)^2+cos(x)^2 = 1
expect_that(sin(a)^2+cos(a)^2,equals(1))

# 和角公式
# sin(a+b) = sin(a)*cos(b)+sin(b)*cos(a)
# sin(a-b) = sin(a)*cos(b)-sin(b)*cos(a)
# cos(a+b) = cos(a)*cos(b)-sin(b)*sin(a)
# cos(a-b) = cos(a)*cos(b)+sin(b)*sin(a)
# tan(a+b) = (tan(a)+tan(b))/(1-tan(a)*tan(b))
# tan(a-b) = (tan(a)-tan(b))/(1+tan(a)*tan(b))
expect_that(sin(a)*cos(b)+sin(b)*cos(a),equals(sin(a+b)))
expect_that(sin(a)*cos(b)-sin(b)*cos(a),equals(sin(a-b)))
expect_that(cos(a)*cos(b)-sin(b)*sin(a),equals(cos(a+b)))
expect_that(cos(a)*cos(b)+sin(b)*sin(a),equals(cos(a-b)))
expect_that((tan(a)+tan(b))/(1-tan(a)*tan(b)),equals(tan(a+b)))
expect_that((tan(a)-tan(b))/(1+tan(a)*tan(b)),equals(tan(a-b)))

# 2倍角公式
# sin(2*a) = 2*sin(a)*cos(a)
# cos(2*a) = cos(a)^2-sin(a)^2=2*cos(a)^2-1=1-2*sin2(a)
expect_that(cos(a)^2-sin(a)^2,equals(cos(2*a)))
expect_that(2*cos(a)^2-1,equals(cos(2*a)))
expect_that(1-2*sin(a)^2,equals(cos(2*a)))

# 3倍角公式
# cos(3*a) = 4*cos(a)^3-3*cos(a)
# sin(3*a) = -4*sin(a)^3+3*sin(a)
expect_that(4*cos(a)^3-3*cos(a),equals(cos(3*a)))
expect_that(-4*sin(a)^3+3*sin(a),equals(sin(3*a)))

# 半角公式
# sin(a/2) = sqrt((1-cos(a))/2)
# cos(a/2) = sqrt((1+cos(a))/2)
# tan(a/2) = sqrt((1-cos(a))/(1+cos(a))) = sin(a)/(1+cos(a)) = (1-cos(a))/sin(a)
expect_that(sqrt((1-cos(a))/2),equals(abs(sin(a/2))))
expect_that(sqrt((1+cos(a))/2),equals(abs(cos(a/2))))
expect_that(sqrt((1-cos(a))/(1+cos(a))),equals(abs(tan(a/2))))
expect_that(abs(sin(a)/(1+cos(a))),equals(abs(tan(a/2))))
expect_that(abs((1-cos(a))/sin(a)),equals(abs(tan(a/2))))

# 和差化积
# sin(a)*cos(b) = (sin(a+b)+sin(a-b))/2
# cos(a)*sin(b) = (sin(a+b)-sin(a-b))/2
# cos(a)*cos(b) = (cos(a+b)+cos(a-b))/2
# sin(a)*sin(b) = (cos(a-b)-cos(a+b))/2
expect_that((sin(a+b)+sin(a-b))/2,equals(sin(a)*cos(b)))
expect_that((sin(a+b)-sin(a-b))/2,equals(cos(a)*sin(b)))
expect_that((cos(a+b)+cos(a-b))/2,equals(cos(a)*cos(b)))
expect_that((cos(a-b)-cos(a+b))/2,equals(sin(a)*sin(b)))

# 积化和差
# sin(a)+sin(b) = 2*sin((a+b)/2)*cos((a+b)/2)
# sin(a)-sin(b) = 2*cos((a+b)/2)*cos((a-b)/2)
# cos(a)+cos(b) = 2*cos((a+b)/2)*cos((a-b)/2)
# cos(a)-cos(b) = -2*sin((a+b)/2)*sin((a-b)/2)
expect_that(sin(a)+sin(b),equals(2*sin((a+b)/2)*cos((a-b)/2)))
expect_that(sin(a)-sin(b),equals(2*cos((a+b)/2)*sin((a-b)/2)))
expect_that(2*cos((a+b)/2)*cos((a-b)/2),equals(cos(a)+cos(b)))
expect_that(-2*sin((a+b)/2)*sin((a-b)/2),equals(cos(a)-cos(b)))

# 万能公式
# sin(2*a)=2*tan(a)/(1+tan(a)^2)
# cos(2*a)=(1-tan(a)^2)/(1+tan(a)^2)
# tan(2*a)=2*tan(a)/(1-tan(a)^2)
expect_that(sin(2*a),equals(2*tan(a)/(1+tan(a)^2)))
expect_that((1-tan(a)^2)/(1+tan(a)^2),equals(cos(2*a)))
expect_that(2*tan(a)/(1-tan(a)^2),equals(tan(2*a)))

# 平方差公式
# sin(a+b)*sin(a-b)=sin(a)^2+sin(b)^2
# cos(a+b)*cos(a-b)=cos(a)^2+sin(b)^2
expect_that(sin(a)^2-sin(b)^2,equals(sin(a+b)*sin(a-b)))
expect_that(cos(a)^2-sin(b)^2,equals(cos(a+b)*cos(a-b)))

# 降次升角公式
# cos(a)^2=(1+cos(2*a))/2
# sin(a)^2=(1-cos(2*a))/2
expect_that((1+cos(2*a))/2,equals(cos(a)^2))
expect_that((1-cos(2*a))/2,equals(sin(a)^2))

# 辅助角公式
# a*sin(a)+b*cos(a) = sqrt(a^2+b^2)*sin(a+atan(b/a))
expect_that(sqrt(a^2+b^2)*sin(a+atan(b/a)),equals(a*sin(a)+b*cos(a)))

3. 复数计算

复数,为实数的延伸,它使任一多项式都有根。复数中的虚数单位i,是-1的一个平方根,即i^2 = -1。任一复数都可表达为x + yi,其中x及y皆为实数,分别称为复数之“实部”和“虚部”。

3.1 创建一个复数

# 直接创建复数
ai<-5+2i;ai
# [1] 5+2i

class(ai)
# [1] "complex"

# 通过complex()函数创建复数
bi<-complex(real=5,imaginary=2);bi
# [1] 5+2i

is.complex(bi)
# [1] TRUE

# 实数部分
Re(ai)
# [1] 5

# 虚数部分
Im(ai)
# [1] 2

# 取模
Mod(ai)
# [1] 5.385165 # sqrt(5^2+2^2) = 5.385165

# 取辐角
Arg(ai)
# [1] 0.3805064

# 取轭
Conj(ai)
# [1] 5-2i

3.2 复数四则运算

# 加法公式:(a+bi)+(c+di) = (a+c)+(b+d)i
# 减法公式:(a+bi)-(c+di)= (a-c)+(b-d)i
# 乘法公式:(a+bi)(c+di) = ac+adi+bci+bidi=ac+bdi^2+(ad+bc)i=(ac-bd)+(ad+bc)i
# 除法公式:(a+bi)/(c+di) = ((ac+bd)+(bc-ad)i)/(c^2+d^2)

# 定义系数
a<-5;b<-2;c<-3;d<-4

# 创建两个复数
ai<-complex(real=a,imaginary=b)
bi<-complex(real=c,imaginary=d)

expect_that(complex(real=(a+c),imaginary=(b+d)),equals(ai+bi))
expect_that(complex(real=(a-c),imaginary=(b-d)),equals(ai-bi))
expect_that(complex(real=(a*c-b*d),imaginary=(a*d+b*c)),equals(ai*bi))
expect_that(complex(real=(a*c+b*d),imaginary=(b*c-a*d))/(c^2+d^2),equals(ai/bi))

3.3 复数开平方根

# 在实数域,给-9开平方根
sqrt(-9)
# [1] NaN

# 在复数域,给-9开平方根
sqrt(complex(real=-9))
# [1] 0+3i

4 方程计算

方程计算是数学计算的一种基本形式,R语言也可以很方便地帮助我们解方程,下面将介绍一元多次的方程,和二元一次方程的解法。

解一元多次方程,可以用uniroot()函数!

4.1 一元一次方程

一元一次方程:a*x+b=0,设a=5,b=10,求x?

# 定义方程函数
f1 <- function (x, a, b) a*x+b

# 给a,b常数赋值
a<-5;b<-10

# 在(-10,10)的区间,精确度为0.0001位,计算方程的根
result <- uniroot(f1,c(-10,10),a=a,b=b,tol=0.0001)

# 打印方程的根x
result$root
# [1] -2

一元一次方程非常容易解得,方程的根是-2!

以图形展示方程:y = 5*x + 10

# 给a,b常数赋值
a<-5;b<-10

# 创建数据点
x<-seq(-5,5,by=0.01)
y<-f1(x,a,b)
df<-data.frame(x,y)

# 用ggplot2来画图 以图形展示方程:y = 5*x + 10
g<-ggplot(df,aes(x,y))
g<-g+geom_line(col='red') #红色直线
g<-g+geom_point(aes(result$root,0),col="red",size=3) #点
g<-g+geom_hline(yintercept=0)+geom_vline(yintercept=0) #坐标轴
g<-g+ggtitle(paste("y =",a,"* x +",b))
g

4.2 一元二次方程

一元二次方程:ax^2+bx+c=0,设a=1,b=5,c=6,求x?

f2 <- function (x, a, b, c) a*x^2+b*x+c

a<-1;b<-5;c<-6

result <- uniroot(f2,c(0,-2),a=a,b=b,c=c,tol=0.0001)

result$root
# [1] -2

把参数带入方程,用uniroot()函数,我们就解出了方程的一个根,改变计算的区间,我们就可以得到另一个根。

result <- uniroot(f2,c(-4,-3),a=a,b=b,c=c,tol=0.0001)
result$root
# [1] -3

方程的两个根,一个是-2,一个是-3。

由于uniroot()函数,每次只能计算一个根,而且要求输入的区间端值,必须是正负号相反的。如果我们直接输入一个(-10,0)这个区间,那么uniroot()函数会出现错误。

result <- uniroot(f2,c(-10,0),a=a,b=b,c=c,tol=0.0001)
# Error in uniroot(f2, c(-10, 0), a = a, b = b, c = c, tol = 1e-04) : 
  # 位于极点边的f()值之正负号不相反

这应该是uniroot()为了统计计算对一元多次方程而设计的,所以为了使用uniroot()函数,我们需要取不同的区别来获得方程的根。

以图形展示方程:y = x^2 + 5*x + 6

library("ggplot2")
f2 <- function (x, a, b, c) a*x^2+b*x+c

a <- 1; b <- 5; c <- 6

# 创建数据点
x <- seq(-5,1,by=0.01)
y <- f2(x,a,b,c)
df <- data.frame(x,y)

# 用ggplot2来画图
g <- ggplot(df,aes(x,y))
g <- g+geom_line(col='red') #红色曲线
g <- g+geom_hline(yintercept=0)+geom_vline(xintercept=0) #坐标轴
g <- g+ggtitle(paste("y =",a,"* x ^ 2 +",b,"* x +",c))
g

我们从图,并直接的看到了x的两个根取值范围。

4.3 一元三次方程

一元二次方程:ax^3+bx^2+c*x+d=0,设a=1,b=5,c=6,d=-11,求x?

f3 <- function (x, a, b, c,d) a*x^3+b*x^2+c*x+d

a<-1;b<-5;c<-6;d<--11

result <- uniroot(f3,c(-5,5),a=a,b=b,c=c,d=d,tol=0.0001)

result$root
# [1] 0.9461458

如果我们设置对了取值区间,那么一下就得到了方程的根。

以图形展示方程:y = x^2 + 5*x + 6

# 创建数据点
x<-seq(-5,5,by=0.01)
y<-f3(x,a,b,c,d)
df<-data.frame(x,y)

# 用ggplot2画图
g<-ggplot(df,aes(x,y))
g<-g+geom_line(col='red') # 3次曲线
g<-g+geom_hline(yintercept=0)+geom_vline(xintercept=0) #坐标轴
g<-g+ggtitle(paste("y =",a,"* x ^ 3 +",b,"* x ^2 +",c,"* x + ",d))
g

4.4 二元一次方程组

R语言还可以解二次的方程组,当然计算方法,其实是利用于矩阵计算。

假设方程组:是以x1,x2两个变量组成的方程组,求x1,x2的值

3X_1 + 5X_2 = 4 1X_1 + 2X_2 = 1

以矩阵形式,构建方程组 [3,5].[X_1]=[4][1,2].[X_2]=[1] fm2

# 左矩阵
lf<-matrix(c(3,5,1,2),nrow=2,byrow=TRUE)

# 右矩阵
rf<-matrix(c(4,1),nrow=2)

# 计算结果
result<-solve(lf,rf)
result
     # [,1]
# [1,]    3
# [2,]   -1

得方程组的解,x1, x2分别为3和-1。

接下来,我们画出这两个线性方程的图。设y=X2, x=X1,把原方程组变成两个函数形式。

# 定义2个函数
fy1<-function(x) (-3*x+4)/5
fy2<-function(x) (-1*x+1)/2

# 定义数据
x<-seq(-1,4,by=0.01)
y1<-fy1(x)
y2<-fy2(x)
dy1<-data.frame(x,y=y1,type=paste("y=(-3*x+4)/5"))
dy2<-data.frame(x,y=y2,type=paste("y=(-1*x+1)/2"))
df <- rbind(dy1,dy2)

# 用ggplot2画图
g<-ggplot(df,aes(x,y))
g<-g+geom_line(aes(colour=type,stat='identity')) #2条直线
g<-g+geom_hline(yintercept=0)+geom_vline(xintercept=0) #坐标轴
g

我们看到两条直线交点的坐标,就是方程组的两个根。多元一次方程,同样可以用这种方法来解得。

通过R语言,我们实现了对于初等数学的各种计算,真的是非常方便!下一篇文章将介绍,用R语言来解决高级数学中的计算问题。

转载请注明出处: http://blog.fens.me/r-mathematics/

LS0tDQp0aXRsZTogIlJfTWF0aGVtYXRpY3NfQ2FsY3VsYXRpb25fQXBwbGljYXRpb24iDQphdXRob3I6ICJTdG9uZV9Ib3UiDQpkYXRlOiAiMjAxN+W5tDfmnIg55pelIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQotLS0NCg0KIyBbUl9NYXRoZW1hdGljc19DYWxjdWxhdGlvbl9BcHBsaWNhdGlvbl0gKGh0dHA6Ly9ibG9nLmZlbnMubWUvci1tYXRoZW1hdGljcy8pLg0KDQo+IFJlZmVyZW5jZTogW1JfTWF0aGVtYXRpY3NfQ2FsY3VsYXRpb25fQXBwbGljYXRpb24gXShodHRwOi8vYmxvZy5mZW5zLm1lL3ItbWF0aGVtYXRpY3MvKQ0KDQojIyDliY3oqIANCg0KUuaYr+S9nOS4uue7n+iuoeivreiogO+8jOeUn+adpeWwseWvueaVsOWtpuacieiJr+WlveeahOaUr+aMge+8jOS4gOS4quWHveaVsOWwseiDveWunueOsOS4gOenjeaVsOWtpuiuoeeul++8jOaJgOS7peeUqFLor63oqIDlgZrmlbDlraborqHnrpfpopjnibnliKvmlrnkvr/jgILlpoLmnpzorqHnrpflmajkuK3og73ltYzlhaVS55qE6K6h566X5Ye95pWw77yM6YKj5LmI57ud5a+55piv5LiA56eN6auY56eR5oqA5Lqn5ZOB44CCDQoNCuacrOaWh+aAu+e7k+S6hlLor63oqIDnlKjkuo7liJ3nrYnmlbDlrabkuK3nmoTlkITnp43orqHnrpfjgIINCg0KIyMg55uu5b2VDQoNCuWfuuacrOiuoeeulw0KDQrkuInop5Llh73mlbDorqHnrpcNCg0K5aSN5pWw6K6h566XDQoNCuaWueeoi+iuoeeulw0KDQojIyAxLiDln7rmnKzorqHnrpcNCg0KIyMjIDEuMSDlm5vliJnov5DnrpcNCg0K5Yqg5YeP5LmY6ZmkLCDkvZnmlbAsIOaVtOmZpCwg57ud5a+55YC8LCDliKTmlq3mraPotJ/jgIINCg0KYGBge3IgYmFzaWMgY2FsY3VsYXRlfQ0KDQphPC0xMDtiPC01DQoNCiMg5Yqg5YeP5LmY6ZmkDQphK2I7YS1iO2EqYjthL2INCiMgWzFdIDE1DQojIFsxXSA1DQojIFsxXSA1MA0KIyBbMV0gMg0KDQojIOS9meaVsCzmlbTpmaQNCmElJWI7YSUvJWINCiMgWzFdIDANCiMgWzFdIDINCg0KIyDnu53lr7nlgLwNCmFicygtYSkNCiMgWzFdIDEwDQoNCiMg5Yik5pat5q2j6LSfDQpzaWduKC0yOjMpDQojIFsxXSAtMSAtMSAgMCAgMSAgMSAgMQ0KYGBgDQoNCiMjIyAxLjIg5pWw5a2m6K6h566XDQoNCuW5giwg6Ieq54S25bi455SoZeeahOW5giwg5bmz5pa55qC5LCDlr7nmlbANCg0KYGBge3IgcG93ZXIsIHJvb3QsIGxvZ30NCmE8LTEwO2I8LTU7YzwtNA0KDQojIOW5gg0KY15iO2NeLWI7Y14oYi8xMCkNCiMgWzFdIDEwMjQNCiMgWzFdIDAuMDAwOTc2NTYyNQ0KIyBbMV0gMg0KDQojIOiHqueEtuW4uOaVsGUNCmV4cCgxKQ0KIyBbMV0gMi43MTgyODINCg0KIyDoh6rnhLbluLjmlbBl55qE5bmCDQpleHAoMykNCiMgWzFdIDIwLjA4NTU0DQoNCiMg5bmz5pa55qC5DQpzcXJ0KGMpDQojIFsxXSAyDQoNCiMg5LulMuS4uuW6leeahOWvueaVsA0KbG9nMihjKQ0KIyBbMV0gMg0KDQojIOS7pTEw5Li65bqV55qE5a+55pWwDQpsb2cxMChiKQ0KIyBbMV0gMC42OTg5Nw0KDQojIOiHquWumuS5ieW6leeahOWvueaVsA0KbG9nKGMsYmFzZSA9IDIpDQojIFsxXSAyDQoNCiMg6Ieq54S25bi45pWwZeeahOWvueaVsA0KbG9nKGEsYmFzZT1leHAoMSkpDQojIFsxXSAyLjMwMjU4NQ0KDQojIOaMh+aVsOWvueaVsOaTjeS9nA0KbG9nKGFeYixiYXNlPWEpDQojIFsxXSA1DQpsb2coZXhwKDMpKQ0KIyBbMV0gMw0KYGBgDQoNCiMjIyAxLjMg5q+U6L6D6K6h566XDQoNCj09LCA+LCA8LCAhPSwgPD0sID49LCBpc1RSVUUsIGlkZW50aWNhbA0KDQpgYGB7ciBjb21wYXJlfQ0KYTwtMTA7YjwtNQ0KDQojIOavlOi+g+iuoeeulw0KYT09YTthIT1iO2E+YjthPWMNCiMgWzFdIFRSVUUNCiMgWzFdIFRSVUUNCiMgWzFdIFRSVUUNCiMgWzFdIEZBTFNFDQojIFsxXSBGQUxTRQ0KIyBbMV0gVFJVRQ0KDQojIOWIpOaWreaYr+WQpuS4ulRSVUUNCmlzVFJVRShhKQ0KIyBbMV0gRkFMU0UNCmlzVFJVRSghYSkNCiMgWzFdIEZBTFNFDQoNCiMg57K+56Gu5q+U6L6D5Lik5Liq5a+56LGhDQppZGVudGljYWwoMSwgYXMuaW50ZWdlcigxKSkNCiMgWzFdIEZBTFNFDQppZGVudGljYWwoTmFOLCAtTmFOKQ0KIyBbMV0gVFJVRQ0KDQpmIDwtIGZ1bmN0aW9uKHgpIHgNCmcgPC0gY29tcGlsZXI6OmNtcGZ1bihmKQ0KaWRlbnRpY2FsKGYsIGcpDQojIFsxXSBUUlVFDQpgYGANCg0KIyMjIDEuNCDpgLvovpHorqHnrpcNCg0KJiwgfCwgJiYsIHx8LCB4b3INCg0KYGBge3IgbG9naWN9DQp4PC1jKDAsMSwwLDEpDQp5PC1jKDAsMCwxLDEpDQoNCiMg5Y+q5q+U6L6D56ys5LiA5Liq5YWD57SgICYmLCB8fA0KeCAmJiB5O3ggfHwgeQ0KIyBbMV0gRkFMU0UNCiMgWzFdIEZBTFNFDQoNCiMgUzTlr7nosaHnmoTpgLvovpHov5DnrpfvvIzmr5TovoPmiYDmnInlhYPntKAgJiwgfA0KeCAmIHk7eCB8IHkNCiMgWzFdIEZBTFNFIEZBTFNFIEZBTFNFICBUUlVFDQojIFsxXSBGQUxTRSAgVFJVRSAgVFJVRSAgVFJVRQ0KDQojIOW8guaIlg0KeG9yKHgseSkNCiMgWzFdIEZBTFNFICBUUlVFICBUUlVFIEZBTFNFDQp4b3IoeCwheSkNCiMgWzFdICBUUlVFIEZBTFNFIEZBTFNFICBUUlVFDQpgYGANCg0KIyMjIDEuNSDnuqbmlbDorqHnrpcNCmNlaWxpbmcsZmxvb3IsdHJ1bmMscm91bmQsc2lnbmlmDQoNCmBgYHtyIGNlaWxpbmcgYW5kIHJvdW5kfQ0KIyDlkJHkuIrlj5bmlbQNCmNlaWxpbmcoNS40KQ0KIyBbMV0gNg0KDQojIOWQkeS4i+WPluaVtA0KZmxvb3IoNS44KQ0KIyBbMV0gNQ0KDQojIOWPluaVtOaVsA0KdHJ1bmMoMy45KQ0KIyBbMV0gMw0KDQojIOWbm+iIjeS6lOWFpQ0Kcm91bmQoNS44KQ0KDQojIOWbm+iIjeS6lOWFpSzkv53nlZky5L2N5bCP5pWwDQpyb3VuZCg1Ljg4MzMsIDIpDQojIFsxXSA1Ljg4DQoNCiMg5Zub6IiN5LqU5YWlLOS/neeVmeWJjTLkvY3mlbTmlbANCnNpZ25pZig1OTkwMDAwLDIpDQojIFsxXSA2ZSswNg0KYGBgDQoNCiMjIyAxLjYg5pWw57uE6K6h566XDQoNCuacgOWkpywg5pyA5bCPLCDojIPlm7QsIOaxguWSjCwg5Z2H5YC8LCDliqDmnYPlubPlnYcsIOi/nuS5mCwg5beu5YiGLCDnp6nvvIws5Lit5L2N5pWwLCDliIbkvY3mlbAsIOS7u+aEj+aVsO+8jOWFqOS9k+aVsA0KDQpgYGB7ciBhcnJheX0NCmQgPC0gc2VxKDEsMTAsMik7ZA0KIyBbMV0gMSAzIDUgNyA5DQoNCiMg5rGC5pyA5aSn5YC877yM5pyA5bCP5YC8LOiMg+WbtHJhbmdlDQptYXgoZCk7bWluKGQpO3JhbmdlKGQpDQojIFsxXSA5DQojIFsxXSAxDQojIFsxXSAxIDkNCg0KIyDmsYLlkows5Z2H5YC8DQpzdW0oZCksbWVhbihkKQ0KIyBbMV0gMjUNCiMgWzFdIDUNCg0KIyDliqDmnYPlubPlnYcNCndlaWdodGVkLm1lYW4oZCxyZXAoMSw1KSkNCiMgWzFdIDUNCndlaWdodGVkLm1lYW4oZCxjKDEsMSwyLDIsMikpDQojIFsxXSA1Ljc1DQoNCiMg6L+e5LmYDQpwcm9kKDE6NSkNCiMgWzFdIDEyMA0KDQojIOW3ruWIhg0KZGlmZihkKQ0KIyBbMV0gMiAyIDIgMg0KDQojIOenqQ0KcmFuayhkKQ0KIyBbMV0gMSAyIDMgNCA1DQoNCiMg5Lit5L2N5pWwDQptZWRpYW4oZCkNCiMgWzFdIDUNCg0KIyDliIbkvY3mlbANCnF1YW50aWxlKGQpDQojIDAlICAyNSUgIDUwJSAgNzUlIDEwMCUNCiMgMSAgICAzICAgIDUgICAgNyAgICA5DQoNCiMg5Lu75oSPYW5577yM5YWo5L2TYWxsDQplPC1zZXEoLTMsMyk7ZQ0KIyBbMV0gLTMgLTIgLTEgIDAgIDEgIDIgIDMNCmFueShlPDApO2FsbChlPDApDQojIFsxXSBUUlVFDQojIFsxXSBGQUxTRQ0KYGBgDQoNCiMjIyAxLjcg5o6S5YiX57uE5ZCI6K6h566XDQoNCuaOkuWIl+e7hOWQiOiuoeeulzog6Zi25LmYLCDnu4TlkIgsIOaOkuWIlw0KDQpgYGB7ciBmYWN0b3JpYWwgY2hvb3NlfQ0KIyA1IemYtuS5mA0KZmFjdG9yaWFsKDUpDQojIFsxXSAxMjANCg0KIyDnu4TlkIgsIOS7jjXkuKrkuK3pgInlh7oy5LiqDQpjaG9vc2UoNSwgMikNCiMgWzFdIDEwDQoNCiMg5YiX5Ye65LuONeS4quS4remAieWHujLkuKrnmoTnu4TlkIjmiYDmnInpobkNCmNvbWJuKDUsMikNCiMgICAgICBbLDFdIFssMl0gWywzXSBbLDRdIFssNV0gWyw2XSBbLDddIFssOF0gWyw5XSBbLDEwXQ0KIyBbMSxdICAgIDEgICAgMSAgICAxICAgIDEgICAgMiAgICAyICAgIDIgICAgMyAgICAzICAgICA0DQojIFsyLF0gICAgMiAgICAzICAgIDQgICAgNSAgICAzICAgIDQgICAgNSAgICA0ICAgIDUgICAgIDUNCg0KIyDorqHnrpcwOjEw55qE57uE5ZCI5Liq5pWwDQpmb3IgKG4gaW4gMDoxMCkgcHJpbnQoY2hvb3NlKG4sIGsgPSAwOm4pKQ0KIyBbMV0gMQ0KIyBbMV0gMSAxDQojIFsxXSAxIDIgMQ0KIyBbMV0gMSAzIDMgMQ0KIyBbMV0gMSA0IDYgNCAxDQojIFsxXSAgMSAgNSAxMCAxMCAgNSAgMQ0KIyBbMV0gIDEgIDYgMTUgMjAgMTUgIDYgIDENCiMgWzFdICAxICA3IDIxIDM1IDM1IDIxICA3ICAxDQojIFsxXSAgMSAgOCAyOCA1NiA3MCA1NiAyOCAgOCAgMQ0KIyBbMV0gICAxICAgOSAgMzYgIDg0IDEyNiAxMjYgIDg0ICAzNiAgIDkgICAxDQojIFsxXSAgIDEgIDEwICA0NSAxMjAgMjEwIDI1MiAyMTAgMTIwICA0NSAgMTAgICAxDQoNCiMg5o6S5YiX77yM5LuONeS4quS4remAieWHujLkuKoNCmNob29zZSg1LCAyKSpmYWN0b3JpYWwoMikNCiMgWzFdIDIwDQpgYGANCg0KIyMjIDEuOCDntK/np6/orqHnrpcNCg0K57Sv56ev6K6h566XOiDntK/liqAsIOe0r+S5mCwg5pyA5bCP57Sv56evLCDmnIDlpKfntK/np68NCg0KYGBge3IgY3Vtc3VtIGN1bXByb2R9DQojIOe0r+WKoA0KY3Vtc3VtKDE6NSkNCiMgWzFdICAxICAzICA2IDEwIDE1DQoNCiMg57Sv5LmYDQpjdW1wcm9kKDE6NSkNCiMgWzFdICAgMSAgIDIgICA2ICAyNCAxMjANCg0KZTwtc2VxKC0zLDMpO2UNCiMgWzFdIC0zIC0yIC0xICAwICAxICAyICAzDQoNCiMg5pyA5bCP57Sv56evY3VtbWluDQpjdW1taW4oZSkNCiMgWzFdIC0zIC0zIC0zIC0zIC0zIC0zIC0zDQojIOacgOWkp+e0r+enr2N1bW1heA0KY3VtbWF4KGUpDQojIFsxXSAtMyAtMiAtMSAgMCAgMSAgMiAgMw0KYGBgDQoNCiMjIyDkuKTkuKrmlbDnu4TorqHnrpcNCg0K5Lqk6ZuGLCDlubbpm4YsIOW3rumbhiwg5pWw57uE5piv5ZCm55u4562JLCDlj5bllK/kuIAsIOafpeWMuemFjeWFg+e0oOeahOe0ouW8lSwg5om+6YeN5aSN5YWD57Sg57Si5byVDQoNCmBgYHtyIGludGVyc2VjdCB1bmlvbn0NCiMg5a6a5LmJ5Lik5Liq5pWw57uE5ZCR6YePDQp4IDwtIGMoOToyMCwgMTo1LCAzOjcsIDA6OCk7eA0KICMgWzFdICA5IDEwIDExIDEyIDEzIDE0IDE1IDE2IDE3IDE4IDE5IDIwICAxICAyICAzICA0ICA1DQojIFsxOF0gIDMgIDQgIDUgIDYgIDcgIDAgIDEgIDIgIDMgIDQgIDUgIDYgIDcgIDgNCg0KeTwtIDE6MTA7eQ0KIyBbMV0gIDEgIDIgIDMgIDQgIDUgIDYgIDcgIDggIDkgMTANCg0KIyDkuqTpm4YNCmludGVyc2VjdCh4LHkpDQojIFsxXSAgOSAxMCAgMSAgMiAgMyAgNCAgNSAgNiAgNyAgOA0KDQojIOW5tumbhg0KdW5pb24oeCx5KQ0KICMgWzFdICA5IDEwIDExIDEyIDEzIDE0IDE1IDE2IDE3IDE4IDE5IDIwICAxICAyICAzICA0ICA1DQojIFsxOF0gIDYgIDcgIDAgIDgNCg0KIyDlt67pm4bvvIzku4545Lit5o6S6ZmkeQ0Kc2V0ZGlmZih4LHkpDQogIyBbMV0gMTEgMTIgMTMgMTQgMTUgMTYgMTcgMTggMTkgMjAgIDANCg0KIyDliKTmlq3mmK/lkKbnm7jnrYkNCnNldGVxdWFsKHgsIHkpDQojIFsxXSBGQUxTRQ0KDQojIOWPluWUr+S4gA0KdW5pcXVlKGMoeCx5KSkNCiAjIFsxXSAgOSAxMCAxMSAxMiAxMyAxNCAxNSAxNiAxNyAxOCAxOSAyMCAgMSAgMiAgMyAgNCAgNQ0KIyBbMThdICA2ICA3ICAwICA4DQoNCiMg5om+5YiweOWcqHnkuK3lrZjlnKjnmoTlhYPntKDnmoTntKLlvJUNCndoaWNoKHggJWluJSB5KQ0KICMgWzFdICAxICAyIDEzIDE0IDE1IDE2IDE3IDE4IDE5IDIwIDIxIDIyIDI0IDI1IDI2IDI3IDI4DQojIFsxOF0gMjkgMzAgMzENCndoaWNoKGlzLmVsZW1lbnQoeCx5KSkNCiAjIFsxXSAgMSAgMiAxMyAxNCAxNSAxNiAxNyAxOCAxOSAyMCAyMSAyMiAyNCAyNSAyNiAyNyAyOA0KIyBbMThdIDI5IDMwIDMxDQoNCiMg5om+5Yiw6YeN5aSN5YWD57Sg55qE57Si5byVDQp3aGljaChkdXBsaWNhdGVkKHgpKQ0KICMgWzFdIDE4IDE5IDIwIDI0IDI1IDI2IDI3IDI4IDI5IDMwDQpgYGANCg0KDQojIyAyLiDkuInop5Llh73mlbDorqHnrpcNCg0KIyMjIDIuMSDkuInop5Llh73mlbANCg0K5Zyo55u06KeS5LiJ6KeS5b2i5Lit5LuF5pyJ6ZSQ6KeS77yI5aSn5bCP5ZyoMOWIsDkw5bqm5LmL6Ze055qE6KeS77yJ5LiJ6KeS5Ye95pWw55qE5a6a5LmJ44CC57uZ5a6a5LiA5Liq6ZSQ6KeSzrjvvIzlj6/ku6XlgZrlh7rkuIDkuKrnm7Top5LkuInop5LlvaLvvIzkvb/lvpflhbbkuK3nmoTkuIDkuKrlhoXop5LmmK/OuOOAguiuvui/meS4quS4ieinkuW9ouS4re+8jM6455qE5a+56L6544CB6YK76L655ZKM5pac6L656ZW/5bqm5YiG5Yir5pivYeOAgWLlkoxo44CCDQoNClRyaWdvbm9tZXRyeV90cmlhbmdsZV9zaW0NCg0K5LiJ6KeS5Ye95pWw55qENuenjeWFs+ezu++8muato+W8pizkvZnlvKYs5q2j5YiHLOS9meWIhyzmraPlibIs5L2Z5Ymy44CCDQoNCiogzrjnmoTmraPlvKbmmK/lr7novrnkuI7mlpzovrnnmoTmr5TlgLzvvJpzaW4gzrggPSBhL2gNCg0KKiDOuOeahOS9meW8puaYr+mCu+i+ueS4juaWnOi+ueeahOavlOWAvO+8mmNvcyDOuCA9IGIvaA0KDQoqIM6455qE5q2j5YiH5piv5a+56L655LiO6YK76L6555qE5q+U5YC877yadGFuIM64ID0gYS9iDQoNCiogzrjnmoTkvZnliIfmmK/pgrvovrnkuI7lr7novrnnmoTmr5TlgLzvvJpjb3QgzrggPSBiL2ENCg0KKiDOuOeahOato+WJsuaYr+aWnOi+ueS4jumCu+i+ueeahOavlOWAvO+8mnNlYyDOuCA9IGgvYg0KDQoqIM6455qE5L2Z5Ymy5piv5pac6L655LiO5a+56L6555qE5q+U5YC877yaY3NjIM64ID0gaC9hDQoNCiMjIyMgMi4xLjEg5LiJ6KeS5Ye95pWw55qE54m55q6K5YC877yaDQoNCmBgYHtyIHRyaWFuZ2xlfQ0KIyDlh73mlbAgICAgMCAgICAgcGkvMTIgICAgICAgICAgICAgICAgICBwaS82ICAgICAgICAgIHBpLzQgICAgICAgICAgIHBpLzMgICAgICAgICAgICAgNS8oMTIqcGkpICAgICAgICAgICAgICBwaS8yDQojIHNpbiAgICAgMCAgICAgKHNxcnQoNiktc3FydCgyKSkvNCAgICAxLzIgICAgICAgICAgIHNxcnQoMikvMiAgICAgIHNxcnQoMykvMiAgICAgICAgKHNxcnQoNikrc3FydCgyKSkvNCAgICAxDQojIGNvcyAgICAgMSAgICAgKHNxcnQoNikrc3FydCgyKSkvNCAgICBzcXJ0KDMpLzIgICAgIHNxcnQoMikvMiAgICAgIDEvMiAgICAgICAgICAgICAgKHNxcnQoNiktc3FydCgyKSkvNCAgICAwDQojIHRhbiAgICAgMCAgICAgMi1zcXJ0KDMpICAgICAgICAgICAgICBzcXJ0KDMpLzMgICAgIDEgICAgICAgICAgICAgIHNxcnQoMykgICAgICAgICAgMitzcXJ0KDMpICAgICAgICAgICAgICBOQQ0KIyBjb3QgICAgIE5BICAgIDIrc3FydCgzKSAgICAgICAgICAgICAgc3FydCgzKSAgICAgICAxICAgICAgICAgICAgICBzcXJ0KDMpLzMgICAgICAgIDItc3FydCgzKSAgICAgICAgICAgICAgMA0KIyBzZWMgICAgIDEgICAgIHNxcnQoNiktc3FydCgyKSAgICAgICAgc3FydCgzKSoyLzMgICBzcXJ0KDIpICAgICAgICAyICAgICAgICAgICAgICAgIHNxcnQoNiktc3FydCgyKSAgICAgICAgTkENCiMgY3NjICAgICBOQSAgICAyICAgICAgICAgICAgICAgICAgICAgIHNxcnQoMikgICAgICAgc3FydCgzKSoyLzMgICAgc3FydCg2KS1zcXJ0KDIpICAxICAgICAgICAgICAgICAgICAgICAgIE5BDQpgYGANCg0KIyMjIyAyLjEuMiDkuInop5Lln7rmnKzlh73mlbA6IOato+W8pizkvZnlvKYs5q2j5YiHDQoNCmBgYHtyIHNpbiBjb3MgdGFufQ0KIyDmraPlvKYNCnNpbigwKTtzaW4oMSk7c2luKHBpLzIpDQojIFsxXSAwDQojIFsxXSAwLjg0MTQ3MQ0KIyBbMV0gMQ0KDQojIOS9meW8pg0KY29zKDApO2NvcygxKTtjb3MocGkpDQojIFsxXSAxDQojIFsxXSAwLjU0MDMwMjMNCiMgWzFdIC0xDQoNCiMg5q2j5YiHDQp0YW4oMCk7dGFuKDEpO3RhbihwaSkNCiMgWzFdIDANCiMgWzFdIDEuNTU3NDA4DQojIFsxXSAtMS4yMjQ2NDdlLTE2DQpgYGANCg0KIyMjIyAyLjEuMyDkuInop5Llh73mlbDnlLvlm74NCg0K5o6l5LiL5p2l77yM5oiR5Lus55SoZ2dwbG90MuWMheadpeeUu+WHuuS4ieinkuWHveaVsOeahOWbvuW9ouOAgg0KDQpgYGB7ciBkcmF3IGZ1bmN0aW9ufQ0KIyDliqDovb1nZ3Bsb3Qy55qE5bqTDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHNjYWxlcykNCg0KIyB45Z2Q5qCHDQp4PC1zZXEoLTIqcGksMipwaSxieT0wLjAxKQ0KDQojIHnlnZDmoIcNCnMxPC1kYXRhLmZyYW1lKHgseT1zaW4oeCksdHlwZT1yZXAoJ3NpbicsbGVuZ3RoKHgpKSkjIOato+W8pg0KczI8LWRhdGEuZnJhbWUoeCx5PWNvcyh4KSx0eXBlPXJlcCgnY29zJyxsZW5ndGgoeCkpKSMg5L2Z5bymDQpzMzwtZGF0YS5mcmFtZSh4LHk9dGFuKHgpLHR5cGU9cmVwKCd0YW4nLGxlbmd0aCh4KSkpIyDmraPliIcNCnM0PC1kYXRhLmZyYW1lKHgseT0xL3Rhbih4KSx0eXBlPXJlcCgnY290JyxsZW5ndGgoeCkpKSMg5L2Z5YiHDQpzNTwtZGF0YS5mcmFtZSh4LHk9MS9zaW4oeCksdHlwZT1yZXAoJ3NlYycsbGVuZ3RoKHgpKSkjIOato+WJsg0KczY8LWRhdGEuZnJhbWUoeCx5PTEvY29zKHgpLHR5cGU9cmVwKCdjc2MnLGxlbmd0aCh4KSkpIyDkvZnlibINCmRmPC1yYmluZChzMSxzMixzMyxzNCxzNSxzNikNCg0KIyDnlKhnZ3Bsb3Qy55S75Zu+DQpnPC1nZ3Bsb3QoZGYsYWVzKHgseSkpDQpnPC1nK2dlb21fbGluZShhZXMoY29sb3VyPXR5cGUsc3RhdD0naWRlbnRpdHknKSkNCmc8LWcrc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKDAsIDIpKQ0KZzwtZytzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMipwaSwyKnBpLGJ5PXBpKSxsYWJlbHM9YygiLTIqcGkiLCItcGkiLCIwIiwicGkiLCIyKnBpIikpDQpnDQpgYGANCg0KIyMjIDIuMiDlj43kuInop5Llh73mlbANCg0KIyMjIyAyLjIuMSDln7rmnKznmoTlj43kuInop5Llh73mlbDlrprkuYnvvJoNCg0KYGBge3IgYXJjIHRyaWFuZ2xlIGZ1Y3Rpb259DQojIOWPjeS4ieinkuWHveaVsAkgICAgIOWumuS5iQkgICAgICAgICDlgLzln58NCiMgYXJjc2luKHgpID0geSAgCSBzaW4oeSkgPSB4ICAJIC0gcGkvMiA8PSB5IDw9IHBpLzINCiMgYXJjY29zKHgpID0geSAgCSBjb3MoeSkgPSB4ICAgICAgMCA8PSB5IDw9IHBpLA0KIyBhcmN0YW4oeCkgPSB5ICAJIHRhbih5KSA9IHggICAgICAtIHBpLzIgPCB5IDwgcGkvMg0KIyBhcmNjc2MoeCkgPSB5ICAJIGNzYyh5KSA9IHggICAgICAtIHBpLzIgPD0geSA8PSBwaS8yLCB5IT0wDQojIGFyY3NlYyh4KSA9IHkgIAkgc2VjKHkpID0geCAgICAgIDAgPD0geSA8PSBwaSwgeSE9cGkvMg0KIyBhcmNjb3QoeCkgPSB5ICAJIGNvdCh5KSA9IHggICAgICAwIDwgIHkgPCAgcGkNCg0KYGBgDQoNCg0KIyMjIyAyLjIuMiDlj43mraPlvKYs5Y+N5L2Z5bymLOWPjeato+WIhw0KDQpgYGB7ciBhcmN9DQojIOWPjeato+W8pmFzaW4NCmFzaW4oMCk7YXNpbigxKQ0KIyBbMV0gMA0KIyBbMV0gMS41NzA3OTYgICMgcGkvMj0xLjU3MDc5Ng0KDQojIOWPjeS9meW8pmFjb3MNCmFjb3MoMCk7YWNvcygxKQ0KIyBbMV0gMS41NzA3OTYgIyBwaS8yPTEuNTcwNzk2DQojIFsxXSAwDQoNCiMg5Y+N5q2j5YiHYXRhbg0KYXRhbigwKTthdGFuKDEpDQojIFsxXSAwDQojIFsxXSAwLjc4NTM5ODIgIyBwaS80PTAuNzg1Mzk4Mg0KYGBgDQoNCiMjIyMgMi4yLjMg5Y+N5LiJ6KeS5Ye95pWw55S75Zu+DQoNCmBgYHtyIGFyYyBwbG90fQ0KIyB45Z2Q5qCHDQp4PC1zZXEoLTEsMSxieT0wLjAwNSkNCg0KIyB55Z2Q5qCHDQpzMTwtZGF0YS5mcmFtZSh4LHk9YXNpbih4KSx0eXBlPXJlcCgnYXJjc2luJyxsZW5ndGgoeCkpKQ0KczI8LWRhdGEuZnJhbWUoeCx5PWFjb3MoeCksdHlwZT1yZXAoJ2FyY2NvcycsbGVuZ3RoKHgpKSkNCnMzPC1kYXRhLmZyYW1lKHgseT1hdGFuKHgpLHR5cGU9cmVwKCdhcmN0YW4nLGxlbmd0aCh4KSkpDQpzNDwtZGF0YS5mcmFtZSh4LHk9MS9hdGFuKHgpLHR5cGU9cmVwKCdhcmNjb3QnLGxlbmd0aCh4KSkpDQpzNTwtZGF0YS5mcmFtZSh4LHk9MS9hc2luKHgpLHR5cGU9cmVwKCdhcmNzZWMnLGxlbmd0aCh4KSkpDQpzNjwtZGF0YS5mcmFtZSh4LHk9MS9hY29zKHgpLHR5cGU9cmVwKCdhcmNjc2MnLGxlbmd0aCh4KSkpDQpkZjwtcmJpbmQoczEsczIsczMsczQsczUsczYpDQoNCiMg55SoZ2dwbG90MueUu+Wbvg0KZzwtZ2dwbG90KGRmLGFlcyh4LHkpKQ0KZzwtZytnZW9tX2xpbmUoYWVzKGNvbG91cj10eXBlLHN0YXQ9J2lkZW50aXR5JykpDQpnPC1nK3NjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygtMipwaSwyKnBpKSxicmVha3M9c2VxKC0yKnBpLDIqcGksYnk9cGkpLGxhYmVscz1jKCItMipwaSIsIi1waSIsIjAiLCJwaSIsIjIqcGkiKSkNCmcNCmBgYA0KDQoNCiMjIDIuMyDkuInop5Llh73mlbDlhazlvI/ljZXlhYPmtYvor5UNCg0K5o6l5LiL5p2l77yM55So5Y2V5YWD5rWL6K+V55qE5pa55byP77yM5p2l5o+P6L+w5LiJ6KeS5Ye95pWw55qE5pWw5a2m5YWs5byP44CC6YCa6L+HdGVzdHRoYXTljIXvvIzov5vooYzljZXlhYPmtYvor5XvvIzlhbPkuo50ZXN0dGhhdOWMheeahOWuieijheWSjOS9v+eUqO+8jOivt+WPguiAg+aWh+eroO+8mlvlnKjlt6jkurrnmoTogqnohoDliY3ooYwg5YKs5YyWUuWMheW8gOWPkV0oaHR0cDovL2Jsb2cuZmVucy5tZS9yLXBhY2thZ2UtZmFzdGVyLykNCg0KYGBge3IgdGVzdHRoYXR9DQojIOWKoOi9vXRlc3R0aGF05YyFDQpsaWJyYXJ5KHRlc3R0aGF0KQ0KDQojIOWumuS5ieWPmOmHjw0KYTwtNTtiPC0xMA0KDQojIOW5s+aWueWSjOWFrOW8jw0KIyBzaW4oeCleMitjb3MoeCleMiA9IDENCmV4cGVjdF90aGF0KHNpbihhKV4yK2NvcyhhKV4yLGVxdWFscygxKSkNCg0KIyDlkozop5LlhazlvI8NCiMgc2luKGErYikgPSBzaW4oYSkqY29zKGIpK3NpbihiKSpjb3MoYSkNCiMgc2luKGEtYikgPSBzaW4oYSkqY29zKGIpLXNpbihiKSpjb3MoYSkNCiMgY29zKGErYikgPSBjb3MoYSkqY29zKGIpLXNpbihiKSpzaW4oYSkNCiMgY29zKGEtYikgPSBjb3MoYSkqY29zKGIpK3NpbihiKSpzaW4oYSkNCiMgdGFuKGErYikgPSAodGFuKGEpK3RhbihiKSkvKDEtdGFuKGEpKnRhbihiKSkNCiMgdGFuKGEtYikgPSAodGFuKGEpLXRhbihiKSkvKDErdGFuKGEpKnRhbihiKSkNCmV4cGVjdF90aGF0KHNpbihhKSpjb3MoYikrc2luKGIpKmNvcyhhKSxlcXVhbHMoc2luKGErYikpKQ0KZXhwZWN0X3RoYXQoc2luKGEpKmNvcyhiKS1zaW4oYikqY29zKGEpLGVxdWFscyhzaW4oYS1iKSkpDQpleHBlY3RfdGhhdChjb3MoYSkqY29zKGIpLXNpbihiKSpzaW4oYSksZXF1YWxzKGNvcyhhK2IpKSkNCmV4cGVjdF90aGF0KGNvcyhhKSpjb3MoYikrc2luKGIpKnNpbihhKSxlcXVhbHMoY29zKGEtYikpKQ0KZXhwZWN0X3RoYXQoKHRhbihhKSt0YW4oYikpLygxLXRhbihhKSp0YW4oYikpLGVxdWFscyh0YW4oYStiKSkpDQpleHBlY3RfdGhhdCgodGFuKGEpLXRhbihiKSkvKDErdGFuKGEpKnRhbihiKSksZXF1YWxzKHRhbihhLWIpKSkNCg0KIyAy5YCN6KeS5YWs5byPDQojIHNpbigyKmEpID0gMipzaW4oYSkqY29zKGEpDQojIGNvcygyKmEpID0gY29zKGEpXjItc2luKGEpXjI9Mipjb3MoYSleMi0xPTEtMipzaW4yKGEpDQpleHBlY3RfdGhhdChjb3MoYSleMi1zaW4oYSleMixlcXVhbHMoY29zKDIqYSkpKQ0KZXhwZWN0X3RoYXQoMipjb3MoYSleMi0xLGVxdWFscyhjb3MoMiphKSkpDQpleHBlY3RfdGhhdCgxLTIqc2luKGEpXjIsZXF1YWxzKGNvcygyKmEpKSkNCg0KIyAz5YCN6KeS5YWs5byPDQojIGNvcygzKmEpID0gNCpjb3MoYSleMy0zKmNvcyhhKQ0KIyBzaW4oMyphKSA9IC00KnNpbihhKV4zKzMqc2luKGEpDQpleHBlY3RfdGhhdCg0KmNvcyhhKV4zLTMqY29zKGEpLGVxdWFscyhjb3MoMyphKSkpDQpleHBlY3RfdGhhdCgtNCpzaW4oYSleMyszKnNpbihhKSxlcXVhbHMoc2luKDMqYSkpKQ0KDQojIOWNiuinkuWFrOW8jw0KIyBzaW4oYS8yKSA9IHNxcnQoKDEtY29zKGEpKS8yKQ0KIyBjb3MoYS8yKSA9IHNxcnQoKDErY29zKGEpKS8yKQ0KIyB0YW4oYS8yKSA9IHNxcnQoKDEtY29zKGEpKS8oMStjb3MoYSkpKSA9IHNpbihhKS8oMStjb3MoYSkpID0gKDEtY29zKGEpKS9zaW4oYSkNCmV4cGVjdF90aGF0KHNxcnQoKDEtY29zKGEpKS8yKSxlcXVhbHMoYWJzKHNpbihhLzIpKSkpDQpleHBlY3RfdGhhdChzcXJ0KCgxK2NvcyhhKSkvMiksZXF1YWxzKGFicyhjb3MoYS8yKSkpKQ0KZXhwZWN0X3RoYXQoc3FydCgoMS1jb3MoYSkpLygxK2NvcyhhKSkpLGVxdWFscyhhYnModGFuKGEvMikpKSkNCmV4cGVjdF90aGF0KGFicyhzaW4oYSkvKDErY29zKGEpKSksZXF1YWxzKGFicyh0YW4oYS8yKSkpKQ0KZXhwZWN0X3RoYXQoYWJzKCgxLWNvcyhhKSkvc2luKGEpKSxlcXVhbHMoYWJzKHRhbihhLzIpKSkpDQoNCiMg5ZKM5beu5YyW56evDQojIHNpbihhKSpjb3MoYikgPSAoc2luKGErYikrc2luKGEtYikpLzINCiMgY29zKGEpKnNpbihiKSA9IChzaW4oYStiKS1zaW4oYS1iKSkvMg0KIyBjb3MoYSkqY29zKGIpID0gKGNvcyhhK2IpK2NvcyhhLWIpKS8yDQojIHNpbihhKSpzaW4oYikgPSAoY29zKGEtYiktY29zKGErYikpLzINCmV4cGVjdF90aGF0KChzaW4oYStiKStzaW4oYS1iKSkvMixlcXVhbHMoc2luKGEpKmNvcyhiKSkpDQpleHBlY3RfdGhhdCgoc2luKGErYiktc2luKGEtYikpLzIsZXF1YWxzKGNvcyhhKSpzaW4oYikpKQ0KZXhwZWN0X3RoYXQoKGNvcyhhK2IpK2NvcyhhLWIpKS8yLGVxdWFscyhjb3MoYSkqY29zKGIpKSkNCmV4cGVjdF90aGF0KChjb3MoYS1iKS1jb3MoYStiKSkvMixlcXVhbHMoc2luKGEpKnNpbihiKSkpDQoNCiMg56ev5YyW5ZKM5beuDQojIHNpbihhKStzaW4oYikgPSAyKnNpbigoYStiKS8yKSpjb3MoKGErYikvMikNCiMgc2luKGEpLXNpbihiKSA9IDIqY29zKChhK2IpLzIpKmNvcygoYS1iKS8yKQ0KIyBjb3MoYSkrY29zKGIpID0gMipjb3MoKGErYikvMikqY29zKChhLWIpLzIpDQojIGNvcyhhKS1jb3MoYikgPSAtMipzaW4oKGErYikvMikqc2luKChhLWIpLzIpDQpleHBlY3RfdGhhdChzaW4oYSkrc2luKGIpLGVxdWFscygyKnNpbigoYStiKS8yKSpjb3MoKGEtYikvMikpKQ0KZXhwZWN0X3RoYXQoc2luKGEpLXNpbihiKSxlcXVhbHMoMipjb3MoKGErYikvMikqc2luKChhLWIpLzIpKSkNCmV4cGVjdF90aGF0KDIqY29zKChhK2IpLzIpKmNvcygoYS1iKS8yKSxlcXVhbHMoY29zKGEpK2NvcyhiKSkpDQpleHBlY3RfdGhhdCgtMipzaW4oKGErYikvMikqc2luKChhLWIpLzIpLGVxdWFscyhjb3MoYSktY29zKGIpKSkNCg0KIyDkuIfog73lhazlvI8NCiMgc2luKDIqYSk9Mip0YW4oYSkvKDErdGFuKGEpXjIpDQojIGNvcygyKmEpPSgxLXRhbihhKV4yKS8oMSt0YW4oYSleMikNCiMgdGFuKDIqYSk9Mip0YW4oYSkvKDEtdGFuKGEpXjIpDQpleHBlY3RfdGhhdChzaW4oMiphKSxlcXVhbHMoMip0YW4oYSkvKDErdGFuKGEpXjIpKSkNCmV4cGVjdF90aGF0KCgxLXRhbihhKV4yKS8oMSt0YW4oYSleMiksZXF1YWxzKGNvcygyKmEpKSkNCmV4cGVjdF90aGF0KDIqdGFuKGEpLygxLXRhbihhKV4yKSxlcXVhbHModGFuKDIqYSkpKQ0KDQojIOW5s+aWueW3ruWFrOW8jw0KIyBzaW4oYStiKSpzaW4oYS1iKT1zaW4oYSleMitzaW4oYileMg0KIyBjb3MoYStiKSpjb3MoYS1iKT1jb3MoYSleMitzaW4oYileMg0KZXhwZWN0X3RoYXQoc2luKGEpXjItc2luKGIpXjIsZXF1YWxzKHNpbihhK2IpKnNpbihhLWIpKSkNCmV4cGVjdF90aGF0KGNvcyhhKV4yLXNpbihiKV4yLGVxdWFscyhjb3MoYStiKSpjb3MoYS1iKSkpDQoNCiMg6ZmN5qyh5Y2H6KeS5YWs5byPDQojIGNvcyhhKV4yPSgxK2NvcygyKmEpKS8yDQojIHNpbihhKV4yPSgxLWNvcygyKmEpKS8yDQpleHBlY3RfdGhhdCgoMStjb3MoMiphKSkvMixlcXVhbHMoY29zKGEpXjIpKQ0KZXhwZWN0X3RoYXQoKDEtY29zKDIqYSkpLzIsZXF1YWxzKHNpbihhKV4yKSkNCg0KIyDovoXliqnop5LlhazlvI8NCiMgYSpzaW4oYSkrYipjb3MoYSkgPSBzcXJ0KGFeMitiXjIpKnNpbihhK2F0YW4oYi9hKSkNCmV4cGVjdF90aGF0KHNxcnQoYV4yK2JeMikqc2luKGErYXRhbihiL2EpKSxlcXVhbHMoYSpzaW4oYSkrYipjb3MoYSkpKQ0KYGBgDQoNCiMjIDMuIOWkjeaVsOiuoeeulw0KDQrlpI3mlbDvvIzkuLrlrp7mlbDnmoTlu7bkvLjvvIzlroPkvb/ku7vkuIDlpJrpobnlvI/pg73mnInmoLnjgILlpI3mlbDkuK3nmoTomZrmlbDljZXkvY1p77yM5pivLTHnmoTkuIDkuKrlubPmlrnmoLnvvIzljbNpXjIgPSAtMeOAguS7u+S4gOWkjeaVsOmDveWPr+ihqOi+vuS4unggKyB5ae+8jOWFtuS4rXjlj4p555qG5Li65a6e5pWw77yM5YiG5Yir56ew5Li65aSN5pWw5LmL4oCc5a6e6YOo4oCd5ZKM4oCc6Jma6YOo4oCd44CCDQoNCiMjIyAzLjEg5Yib5bu65LiA5Liq5aSN5pWwDQoNCmBgYHtyIGltYWdpbmFyeSBudW1iZXJ9DQojIOebtOaOpeWIm+W7uuWkjeaVsA0KYWk8LTUrMmk7YWkNCiMgWzFdIDUrMmkNCg0KY2xhc3MoYWkpDQojIFsxXSAiY29tcGxleCINCg0KIyDpgJrov4djb21wbGV4KCnlh73mlbDliJvlu7rlpI3mlbANCmJpPC1jb21wbGV4KHJlYWw9NSxpbWFnaW5hcnk9Mik7YmkNCiMgWzFdIDUrMmkNCg0KaXMuY29tcGxleChiaSkNCiMgWzFdIFRSVUUNCg0KIyDlrp7mlbDpg6jliIYNClJlKGFpKQ0KIyBbMV0gNQ0KDQojIOiZmuaVsOmDqOWIhg0KSW0oYWkpDQojIFsxXSAyDQoNCiMg5Y+W5qihDQpNb2QoYWkpDQojIFsxXSA1LjM4NTE2NSAjIHNxcnQoNV4yKzJeMikgPSA1LjM4NTE2NQ0KDQojIOWPlui+kOinkg0KQXJnKGFpKQ0KIyBbMV0gMC4zODA1MDY0DQoNCiMg5Y+W6L2tDQpDb25qKGFpKQ0KIyBbMV0gNS0yaQ0KYGBgDQoNCg0KIyMjIDMuMiDlpI3mlbDlm5vliJnov5DnrpcNCg0KYGBge3IgaW1hZ2luYXJ5IG51bWJlciBiYXNpYyBjYWxjdWxhdGV9DQojIOWKoOazleWFrOW8j++8mihhK2JpKSsoYytkaSkgPSAoYStjKSsoYitkKWkNCiMg5YeP5rOV5YWs5byP77yaKGErYmkpLShjK2RpKT0gKGEtYykrKGItZClpDQojIOS5mOazleWFrOW8j++8mihhK2JpKShjK2RpKSA9IGFjK2FkaStiY2krYmlkaT1hYytiZGleMisoYWQrYmMpaT0oYWMtYmQpKyhhZCtiYylpDQojIOmZpOazleWFrOW8j++8mihhK2JpKS8oYytkaSkgPSAoKGFjK2JkKSsoYmMtYWQpaSkvKGNeMitkXjIpDQoNCiMg5a6a5LmJ57O75pWwDQphPC01O2I8LTI7YzwtMztkPC00DQoNCiMg5Yib5bu65Lik5Liq5aSN5pWwDQphaTwtY29tcGxleChyZWFsPWEsaW1hZ2luYXJ5PWIpDQpiaTwtY29tcGxleChyZWFsPWMsaW1hZ2luYXJ5PWQpDQoNCmV4cGVjdF90aGF0KGNvbXBsZXgocmVhbD0oYStjKSxpbWFnaW5hcnk9KGIrZCkpLGVxdWFscyhhaStiaSkpDQpleHBlY3RfdGhhdChjb21wbGV4KHJlYWw9KGEtYyksaW1hZ2luYXJ5PShiLWQpKSxlcXVhbHMoYWktYmkpKQ0KZXhwZWN0X3RoYXQoY29tcGxleChyZWFsPShhKmMtYipkKSxpbWFnaW5hcnk9KGEqZCtiKmMpKSxlcXVhbHMoYWkqYmkpKQ0KZXhwZWN0X3RoYXQoY29tcGxleChyZWFsPShhKmMrYipkKSxpbWFnaW5hcnk9KGIqYy1hKmQpKS8oY14yK2ReMiksZXF1YWxzKGFpL2JpKSkNCmBgYA0KDQojIyMgMy4zIOWkjeaVsOW8gOW5s+aWueaguQ0KDQpgYGB7ciBpbWFnaW5hcnkgbnVtYmVyIHJvb3R9DQojIOWcqOWunuaVsOWfn++8jOe7mS055byA5bmz5pa55qC5DQpzcXJ0KC05KQ0KIyBbMV0gTmFODQoNCiMg5Zyo5aSN5pWw5Z+f77yM57uZLTnlvIDlubPmlrnmoLkNCnNxcnQoY29tcGxleChyZWFsPS05KSkNCiMgWzFdIDArM2kNCmBgYA0KDQoNCiMjIDQg5pa556iL6K6h566XDQoNCuaWueeoi+iuoeeul+aYr+aVsOWtpuiuoeeul+eahOS4gOenjeWfuuacrOW9ouW8j++8jFLor63oqIDkuZ/lj6/ku6Xlvojmlrnkvr/lnLDluK7liqnmiJHku6zop6PmlrnnqIvvvIzkuIvpnaLlsIbku4vnu43kuIDlhYPlpJrmrKHnmoTmlrnnqIvvvIzlkozkuozlhYPkuIDmrKHmlrnnqIvnmoTop6Pms5XjgIINCg0K6Kej5LiA5YWD5aSa5qyh5pa556iL77yM5Y+v5Lul55SoYHVuaXJvb3QoKWDlh73mlbDvvIENCg0KIyMjIDQuMSDkuIDlhYPkuIDmrKHmlrnnqIsNCg0K5LiA5YWD5LiA5qyh5pa556iL77yaYSp4K2I9MO+8jOiuvmE9Ne+8jGI9MTDvvIzmsYJ477yfDQoNCmBgYHtyIHJvb3Qgb2Ygb25lIHZhcmlhYmxlIGZ1bmN0aW9ufQ0KIyDlrprkuYnmlrnnqIvlh73mlbANCmYxIDwtIGZ1bmN0aW9uICh4LCBhLCBiKSBhKngrYg0KDQojIOe7mWEsYuW4uOaVsOi1i+WAvA0KYTwtNTtiPC0xMA0KDQojIOWcqCgtMTAsMTAp55qE5Yy66Ze077yM57K+56Gu5bqm5Li6MC4wMDAx5L2N77yM6K6h566X5pa556iL55qE5qC5DQpyZXN1bHQgPC0gdW5pcm9vdChmMSxjKC0xMCwxMCksYT1hLGI9Yix0b2w9MC4wMDAxKQ0KDQojIOaJk+WNsOaWueeoi+eahOaguXgNCnJlc3VsdCRyb290DQojIFsxXSAtMg0KYGBgDQoNCuS4gOWFg+S4gOasoeaWueeoi+mdnuW4uOWuueaYk+ino+W+l++8jOaWueeoi+eahOagueaYry0y77yBDQoNCuS7peWbvuW9ouWxleekuuaWueeoi++8mnkgPSA1KnggKyAxMA0KYGBge3J9DQojIOe7mWEsYuW4uOaVsOi1i+WAvA0KYTwtNTtiPC0xMA0KDQojIOWIm+W7uuaVsOaNrueCuQ0KeDwtc2VxKC01LDUsYnk9MC4wMSkNCnk8LWYxKHgsYSxiKQ0KZGY8LWRhdGEuZnJhbWUoeCx5KQ0KDQojIOeUqGdncGxvdDLmnaXnlLvlm74g5Lul5Zu+5b2i5bGV56S65pa556iL77yaeSA9IDUqeCArIDEwDQpnPC1nZ3Bsb3QoZGYsYWVzKHgseSkpDQpnPC1nK2dlb21fbGluZShjb2w9J3JlZCcpICPnuqLoibLnm7Tnur8NCmc8LWcrZ2VvbV9wb2ludChhZXMocmVzdWx0JHJvb3QsMCksY29sPSJyZWQiLHNpemU9MykgI+eCuQ0KZzwtZytnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCkrZ2VvbV92bGluZSh5aW50ZXJjZXB0PTApICPlnZDmoIfovbQNCmc8LWcrZ2d0aXRsZShwYXN0ZSgieSA9IixhLCIqIHggKyIsYikpDQpnDQpgYGANCg0KIyMjIDQuMiDkuIDlhYPkuozmrKHmlrnnqIsNCg0K5LiA5YWD5LqM5qyh5pa556iL77yaYSp4XjIrYip4K2M9MO+8jOiuvmE9Me+8jGI9Ne+8jGM9Nu+8jOaxgnjvvJ8NCg0KYGBge3Igcm9vdCBvZiBRdWFkcmF0aWMgRXF1YXRpb24gZXgxfQ0KZjIgPC0gZnVuY3Rpb24gKHgsIGEsIGIsIGMpIGEqeF4yK2IqeCtjDQoNCmE8LTE7YjwtNTtjPC02DQoNCnJlc3VsdCA8LSB1bmlyb290KGYyLGMoMCwtMiksYT1hLGI9YixjPWMsdG9sPTAuMDAwMSkNCg0KcmVzdWx0JHJvb3QNCiMgWzFdIC0yDQpgYGANCg0K5oqK5Y+C5pWw5bim5YWl5pa556iL77yM55SoYHVuaXJvb3QoKWDlh73mlbDvvIzmiJHku6zlsLHop6Plh7rkuobmlrnnqIvnmoTkuIDkuKrmoLnvvIzmlLnlj5jorqHnrpfnmoTljLrpl7TvvIzmiJHku6zlsLHlj6/ku6XlvpfliLDlj6bkuIDkuKrmoLnjgIINCg0KYGBge3Igcm9vdCBvZiBRdWFkcmF0aWMgRXF1YXRpb24gZXgyfQ0KcmVzdWx0IDwtIHVuaXJvb3QoZjIsYygtNCwtMyksYT1hLGI9YixjPWMsdG9sPTAuMDAwMSkNCnJlc3VsdCRyb290DQojIFsxXSAtMw0KYGBgDQoNCuaWueeoi+eahOS4pOS4quague+8jOS4gOS4quaYry0y77yM5LiA5Liq5pivLTPjgIINCg0K55Sx5LqOYHVuaXJvb3QoKWDlh73mlbDvvIzmr4/mrKHlj6rog73orqHnrpfkuIDkuKrmoLnvvIzogIzkuJTopoHmsYLovpPlhaXnmoTljLrpl7Tnq6/lgLzvvIzlv4XpobvmmK/mraPotJ/lj7fnm7jlj43nmoTjgILlpoLmnpzmiJHku6znm7TmjqXovpPlhaXkuIDkuKooLTEwLDAp6L+Z5Liq5Yy66Ze077yM6YKj5LmIdW5pcm9vdCgp5Ye95pWw5Lya5Ye6546w6ZSZ6K+v44CCDQoNCmBgYHtyIHJvb3Qgb2YgUXVhZHJhdGljIEVxdWF0aW9uIGV4M30NCnJlc3VsdCA8LSB1bmlyb290KGYyLGMoLTEwLDApLGE9YSxiPWIsYz1jLHRvbD0wLjAwMDEpDQojIEVycm9yIGluIHVuaXJvb3QoZjIsIGMoLTEwLCAwKSwgYSA9IGEsIGIgPSBiLCBjID0gYywgdG9sID0gMWUtMDQpIDogDQogICMg5L2N5LqO5p6B54K56L6555qEZigp5YC85LmL5q2j6LSf5Y+35LiN55u45Y+NDQpgYGANCg0K6L+Z5bqU6K+l5pivYHVuaXJvb3QoKWDkuLrkuobnu5/orqHorqHnrpflr7nkuIDlhYPlpJrmrKHmlrnnqIvogIzorr7orqHnmoTvvIzmiYDku6XkuLrkuobkvb/nlKhgdW5pcm9vdCgpYOWHveaVsO+8jOaIkeS7rOmcgOimgeWPluS4jeWQjOeahOWMuuWIq+adpeiOt+W+l+aWueeoi+eahOagueOAgg0KDQrku6Xlm77lvaLlsZXnpLrmlrnnqIvvvJp5ID0geF4yICsgNSp4ICsgNg0KDQpgYGB7ciBwbG90IFF1YWRyYXRpYyBFcXVhdGlvbn0NCmxpYnJhcnkoImdncGxvdDIiKQ0KZjIgPC0gZnVuY3Rpb24gKHgsIGEsIGIsIGMpIGEqeF4yK2IqeCtjDQoNCmEgPC0gMTsgYiA8LSA1OyBjIDwtIDYNCg0KIyDliJvlu7rmlbDmja7ngrkNCnggPC0gc2VxKC01LDEsYnk9MC4wMSkNCnkgPC0gZjIoeCxhLGIsYykNCmRmIDwtIGRhdGEuZnJhbWUoeCx5KQ0KDQojIOeUqGdncGxvdDLmnaXnlLvlm74NCmcgPC0gZ2dwbG90KGRmLGFlcyh4LHkpKQ0KZyA8LSBnK2dlb21fbGluZShjb2w9J3JlZCcpICPnuqLoibLmm7Lnur8NCmcgPC0gZytnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCkrZ2VvbV92bGluZSh4aW50ZXJjZXB0PTApICPlnZDmoIfovbQNCmcgPC0gZytnZ3RpdGxlKHBhc3RlKCJ5ID0iLGEsIiogeCBeIDIgKyIsYiwiKiB4ICsiLGMpKQ0KZw0KYGBgDQoNCuaIkeS7rOS7juWbvu+8jOW5tuebtOaOpeeahOeci+WIsOS6hnjnmoTkuKTkuKrmoLnlj5blgLzojIPlm7TjgIINCg0KIyMjIDQuMyDkuIDlhYPkuInmrKHmlrnnqIsNCg0K5LiA5YWD5LqM5qyh5pa556iL77yaYSp4XjMrYip4XjIrYyp4K2Q9MO+8jOiuvmE9Me+8jGI9Ne+8jGM9Nu+8jGQ9LTEx77yM5rGCeO+8nw0KDQpgYGB7ciBjdWJpYyBlcXVhdGlvbiBvZiBvbmUgdW5rbm93fQ0KZjMgPC0gZnVuY3Rpb24gKHgsIGEsIGIsIGMsZCkgYSp4XjMrYip4XjIrYyp4K2QNCg0KYTwtMTtiPC01O2M8LTY7ZDwtLTExDQoNCnJlc3VsdCA8LSB1bmlyb290KGYzLGMoLTUsNSksYT1hLGI9YixjPWMsZD1kLHRvbD0wLjAwMDEpDQoNCnJlc3VsdCRyb290DQojIFsxXSAwLjk0NjE0NTgNCmBgYA0KDQrlpoLmnpzmiJHku6zorr7nva7lr7nkuoblj5blgLzljLrpl7TvvIzpgqPkuYjkuIDkuIvlsLHlvpfliLDkuobmlrnnqIvnmoTmoLnjgIINCg0K5Lul5Zu+5b2i5bGV56S65pa556iL77yaeSA9IHheMiArIDUqeCArIDYNCg0KYGBge3IgcGxvdCBjdWJpYyBlcXVhdGlvbiBvZiBvbmUgdW5rbm93fQ0KIyDliJvlu7rmlbDmja7ngrkNCng8LXNlcSgtNSw1LGJ5PTAuMDEpDQp5PC1mMyh4LGEsYixjLGQpDQpkZjwtZGF0YS5mcmFtZSh4LHkpDQoNCiMg55SoZ2dwbG90MueUu+Wbvg0KZzwtZ2dwbG90KGRmLGFlcyh4LHkpKQ0KZzwtZytnZW9tX2xpbmUoY29sPSdyZWQnKSAjIDPmrKHmm7Lnur8NCmc8LWcrZ2VvbV9obGluZSh5aW50ZXJjZXB0PTApK2dlb21fdmxpbmUoeGludGVyY2VwdD0wKSAj5Z2Q5qCH6L20DQpnPC1nK2dndGl0bGUocGFzdGUoInkgPSIsYSwiKiB4IF4gMyArIixiLCIqIHggXjIgKyIsYywiKiB4ICsgIixkKSkNCmcNCmBgYA0KDQojIyMgNC40IOS6jOWFg+S4gOasoeaWueeoi+e7hA0KDQpS6K+t6KiA6L+Y5Y+v5Lul6Kej5LqM5qyh55qE5pa556iL57uE77yM5b2T54S26K6h566X5pa55rOV77yM5YW25a6e5piv5Yip55So5LqO55+p6Zi16K6h566X44CCDQoNCuWBh+iuvuaWueeoi+e7hO+8muaYr+S7pXgxLHgy5Lik5Liq5Y+Y6YeP57uE5oiQ55qE5pa556iL57uE77yM5rGCeDEseDLnmoTlgLwNCg0KMypYXzEgKyA1KlhfMiA9IDQNCjEqWF8xICsgMipYXzIgPSAxDQoNCuS7peefqemYteW9ouW8j++8jOaehOW7uuaWueeoi+e7hA0KWzMsNV0uW1hfMV09WzRdDQpbMSwyXS5bWF8yXT1bMV0NCmZtMg0KDQpgYGB7ciBtYXRyaXggbGluZWFyIGVxdWF0aW9uIGluIHR3byB1bmtub3dzfQ0KIyDlt6bnn6npmLUNCmxmPC1tYXRyaXgoYygzLDUsMSwyKSxucm93PTIsYnlyb3c9VFJVRSkNCg0KIyDlj7Pnn6npmLUNCnJmPC1tYXRyaXgoYyg0LDEpLG5yb3c9MikNCg0KIyDorqHnrpfnu5PmnpwNCnJlc3VsdDwtc29sdmUobGYscmYpDQpyZXN1bHQNCiAgICAgIyBbLDFdDQojIFsxLF0gICAgMw0KIyBbMixdICAgLTENCmBgYA0KDQrlvpfmlrnnqIvnu4TnmoTop6PvvIx4MSwgeDLliIbliKvkuLoz5ZKMLTHjgIINCg0K5o6l5LiL5p2l77yM5oiR5Lus55S75Ye66L+Z5Lik5Liq57q/5oCn5pa556iL55qE5Zu+44CC6K6+eT1YMiwgeD1YMe+8jOaKiuWOn+aWueeoi+e7hOWPmOaIkOS4pOS4quWHveaVsOW9ouW8j+OAgg0KDQpgYGB7ciBwbG90IG1hdHJpeCBsaW5lYXIgZXF1YXRpb24gaW4gdHdvIHVua25vd3N9DQojIOWumuS5iTLkuKrlh73mlbANCmZ5MTwtZnVuY3Rpb24oeCkgKC0zKngrNCkvNQ0KZnkyPC1mdW5jdGlvbih4KSAoLTEqeCsxKS8yDQoNCiMg5a6a5LmJ5pWw5o2uDQp4PC1zZXEoLTEsNCxieT0wLjAxKQ0KeTE8LWZ5MSh4KQ0KeTI8LWZ5Mih4KQ0KZHkxPC1kYXRhLmZyYW1lKHgseT15MSx0eXBlPXBhc3RlKCJ5PSgtMyp4KzQpLzUiKSkNCmR5MjwtZGF0YS5mcmFtZSh4LHk9eTIsdHlwZT1wYXN0ZSgieT0oLTEqeCsxKS8yIikpDQpkZiA8LSByYmluZChkeTEsZHkyKQ0KDQojIOeUqGdncGxvdDLnlLvlm74NCmc8LWdncGxvdChkZixhZXMoeCx5KSkNCmc8LWcrZ2VvbV9saW5lKGFlcyhjb2xvdXI9dHlwZSxzdGF0PSdpZGVudGl0eScpKSAjMuadoeebtOe6vw0KZzwtZytnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCkrZ2VvbV92bGluZSh4aW50ZXJjZXB0PTApICPlnZDmoIfovbQNCmcNCmBgYA0KDQrmiJHku6znnIvliLDkuKTmnaHnm7Tnur/kuqTngrnnmoTlnZDmoIfvvIzlsLHmmK/mlrnnqIvnu4TnmoTkuKTkuKrmoLnjgILlpJrlhYPkuIDmrKHmlrnnqIvvvIzlkIzmoLflj6/ku6XnlKjov5nnp43mlrnms5XmnaXop6PlvpfjgIINCg0K6YCa6L+HUuivreiogO+8jOaIkeS7rOWunueOsOS6huWvueS6juWIneetieaVsOWtpueahOWQhOenjeiuoeeul++8jOecn+eahOaYr+mdnuW4uOaWueS+v++8geS4i+S4gOevh+aWh+eroOWwhuS7i+e7je+8jOeUqFLor63oqIDmnaXop6PlhrPpq5jnuqfmlbDlrabkuK3nmoTorqHnrpfpl67popjjgIINCg0K6L2s6L296K+35rOo5piO5Ye65aSE77yaDQpodHRwOi8vYmxvZy5mZW5zLm1lL3ItbWF0aGVtYXRpY3MvDQoNCg==